<?php

namespace App\Http\Controllers\Api;

use App\Enum\CityEnableEnum;
use App\Enum\CodeEnum;
use App\Enum\OrderEnum;
use App\Enum\RedisEnum;
use App\Enum\TravelEnum;
use App\Http\Controllers\Controller;
use App\Models\VillagerUserModel;
use App\Services\Factory\login\Factory;
use App\Services\PublikService;
use App\Services\Tools\HelpService;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class ApiBaseController extends Controller
{
    private const CACHE_VALID_FIELD='code';
    /**
     * 获取平台工厂-方便调用
     * @throws \Exception
     * @author ninetyseven.
     * @date 2023-04-10 23:36
     */
    public static function getServiceObj()
    {
        $platform = self::getPlatformId();
        return Factory::create($platform);
    }

    /**
     * 获取平台名称
     * @return mixed
     * @author ninetyseven.
     * @date 2023-03-29 23:36
     */
    public static function getPlatformName()
    {
        return TravelEnum::APP_PLATFORM_ID[request()->header('app-platform-id')];
    }

    /**
     * 获取平台id
     * @return mixed
     * @author ninetyseven.
     * @date 2023-03-29 23:37
     */
    public static function getPlatformId()
    {
        return request()->header('app-platform-id');
    }
    public static function validUserAccess($userId)
    {
        // .env 的手机号
        $envGreenPhones = env('GREEN_PHONES',[]);
        if(!empty($envGreenPhones))$envGreenPhones=explode(',', $envGreenPhones);

        // 程序中的手机号,合并.ENV中手机号
        $envGreenPhones = array_merge($envGreenPhones, OrderEnum::INNER_PHONES);

        // 公测结束后，只有INNER_PHONES 能进入 .part 1.
        $userinfo = VillagerUserModel::query()->where('id', $userId)->first();
        if (time() > strtotime(OrderEnum::WX_APP_START_DATE_STOP)
            && time() < strtotime(OrderEnum::WX_APP_END_DATE_STOP)
            && !in_array($userinfo->phone, $envGreenPhones)
        ) {
            throw new \Exception(sprintf(OrderEnum::WX_APP_STOP_MESSAGE,$userinfo->phone), CodeEnum::BUSINESS_ERROR );
        }
    }

    /**
     * @param string $redisKey
     * @param int $ttl
     * @param Object $target
     * @param string $method
     * @param $params - $params['perPage'] = true代表要分页
     * @param Request|null $request
     * @param bool $cacheEmpty
     * @return mixed
     * @throws Exception
     */
    protected static function _cacheableData(string $redisKey, int $ttl, Object $target, string $method, $params, Request $request=null, bool $cacheEmpty=false)
    {
        try {
            $redis = app("redis.connection");
            // 主动穿透redis
            if( !( !empty($request) && !empty($request->penetrate) && $request->penetrate == env('R_PENETRATE_KEY',RedisEnum::R_PENETRATE_KEY)) ) {
                // 从redis 读取它
                $data = $redis->get($redisKey);
                if (!empty($data)) {
                    Log::notice(sprintf('CACHED-DATA, [METHOD=%s], [params=>%s', $method, var_export($params,true) ) );
                    return json_decode($data, true);
                }
            }

            // 调用方法 获取它
            if( is_callable([$target,$method]) ) $result = $target::$method($params);
            else{
                throw new Exception(sprintf("静态方法不存在 %s::%s", $target->toString(), $method));
            }

            // 分页
            if( is_array($params)) {
                $perPage = $params['perPage'] ?? false;
                if ($perPage) {
                    Log::notice("FALSE LOG: ".var_export($params,true));
                    $result = HelpService::resultsPage($result);
                }
            }

            // 缓存 它
            if( $cacheEmpty || !empty($result) )
                $redis->set($redisKey, json_encode($result, JSON_UNESCAPED_UNICODE), 'EX', $ttl);

            return $result;
        }catch (Exception | ContainerExceptionInterface | NotFoundExceptionInterface $e ){
            throw new Exception('缓存数据失败'.$e->getMessage());
        }
    }

    /**
     * 只绑在code等于cacheCode的内容
     *
     * @param string $redisKey
     * @param int $ttl
     * @param Object $target
     * @param string $method
     * @param $params
     * @param  $cacheValid
     * @param string $cacheField
     * @return mixed
     * @throws Exception
     */
    protected static function _cacheableRemoteData(string $redisKey, int $ttl, Object $target, string $method, $params, $cacheValid, string $cacheField=self::CACHE_VALID_FIELD)
    {
        try {
            $redis = app("redis.connection");
            // 从redis 读取它
            $data = $redis->get($redisKey);
            if (!empty($data)) {
                Log::notice(sprintf('CACHED-DATA, [METHOD=%-20s], [params=>%s', $method, var_export($params,true) ) );
                return json_decode($data, true);
            }

            // 调用方法 获取它
            // 调用方法 获取它
            if( is_callable([$target,$method],false) ) {
                $result = $target->$method($params);
            }
            else{
                throw new Exception(sprintf("方法不存在 %s::%s", $target->toString(), $method));
            }

            // 缓存 它
            if( $result[$cacheField] === $cacheValid ) {
                $redis->set($redisKey, json_encode($result, JSON_UNESCAPED_UNICODE), 'EX', $ttl);
            }

            return $result;
        }catch (Exception | ContainerExceptionInterface | NotFoundExceptionInterface $e ){
            throw new Exception('缓存数据失败'.$e->getMessage());
        }
    }
    /**
     * 验证城市来源，转为合法数据。（直辖市code降级）
     *
     * @param Request $request
     * @return mixed
     * @throws \Exception
     */
    protected static function _validCitySource(Request $request){
        if( empty($request->city) ) {
            throw new Exception("城市来源未填写");
        }

        $cityCode = self::cityCodeDown($request->city);

        $result = self::_cacheableData(
            RedisEnum::R_CITY_ENABLED_KEY
            ,RedisEnum::R_CITY_ENABLED_TO
            , (new PublikService)
            ,'getCityEnabled'
            , ''
            , $request
        );
        $allCodes =  array_column($result,'city_code') ;
        if( !in_array($cityCode,$allCodes) ){
            Log::error(sprintf('城市来源(%s)出错,all code=>%s', $cityCode,var_export($allCodes,true)));
            throw new \Exception("城市来源出错");
        }
        return $cityCode;
    }

    /**
     * 结果城市中直辖市升级
     * @param array $rows 二维
     * @return array
     */
    protected static function cityCodeUp(array $rows): array
    {
        Log::info("等升级code = ".var_export($rows,true));
        foreach ($rows as $key => $row) {
            if (in_array($row['city_code'], array_keys(CityEnableEnum::MUNICIPALITY_CITY_UP)))
                $rows[$key]['city_code'] = CityEnableEnum::MUNICIPALITY_CITY_UP[$row['city_code']];
        }

        return $rows;
    }

    /**
     * 直辖市 降级
     * @param $cityCode
     * @return mixed|string
     */
    protected static function cityCodeDown($cityCode)
    {
        if(in_array( $cityCode, array_keys(CityEnableEnum::MUNICIPALITY_CITY_DOWN)))
            $cityCode = CityEnableEnum::MUNICIPALITY_CITY_DOWN[$cityCode];

        return $cityCode;
    }
    private function _getFormatCityCodeUP($result)
    {

    }

}
